#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "LinkedList.h"


/*------------------------------------------ Node */
/*------------------------------------------ Node */

Node *newNode() {
	Node *node = malloc(sizeof(Node));
	node->next = NULL;
	node->prev = NULL;
	node->data = 0;
	node->id = -1;

	return node;
}
Node *initNode(Node *n, float data) {
	n->id = NODE_IDS++;
	n->data = data;

	return n;
}
Node *getNode(float data) {
	Node *n = newNode();
	return initNode(n, data);
}
void deleteNode(Node *n) {
	free(n);
}

void setNodeData(Node *n, float data) {
	n->data = data;
}
void dumpNode(Node *n) {
	printf("\nNode -- id:%d, data:%f\n", n->id, n->data);
}

int hasNext(Node *n) {
	if(n->next==NULL) return 0;
	else return 1;
}
int hasPrev(Node *n) {
	if(n->prev==NULL) return 0;
	else return 1;
}


/*------------------------------------------ List */
/*------------------------------------------ List */

List *newList() {
	List *l = malloc(sizeof(List));
	l->head = l->tail = NULL;
	l->size = 0;

	return l;
}
List *initList(List *l, Node *head) {
	l->head = l->tail = head;
	l->size = 1;

	return l;
}
List *getList(Node *head) {
	return initList(newList(), head);
}
void deleteList(List *l) {
	Iterator *itr = getIterator(l);
	
	itr->current = l->head;
	 while(moveNext(itr)==1) {
		deleteNode(itr->current->prev);
	}

	deleteIterator(itr);
	free(l);
}

Node *getHead(List *l) {
	return l->head;
}
Node *getTail(List *l) {
	return l->tail;
}
void dumpHeadTail(List *l) {
	if(l->size==0) {
		printf("Empy List");
	} else {
		dumpNode(l->head);
		dumpNode(l->tail);
	}
}

void addInHead(List *l, Node *n) {
	if(l->size==0) {
		l->head = l->tail = n;
	} else {
		n->next = l->head;
		l->head->prev = n;
		l->head = n;
	}
	n->prev = NULL;
	l->size++;
}
Node *removeHead(List *l) {
	if(l->size==0) {
		printf("List -- Error! Trying to remove from empty list");
	} else {
		Node *oldHead = l->head;
		Node *newHead = oldHead->next;
		l->head = newHead;
		l->size--;
		if(newHead!=NULL) {
			newHead->prev = NULL;
		} else {
			l->head = l->tail = NULL;
		}
		return oldHead;
	}
	return (Node *)NULL;
}
void addInTail(List *l, Node *n) {
	if(l->size==0) {
		l->head = l->tail = n;
	} else {
		n->prev = l->tail;
		n->next = NULL;
		l->tail->next = n;
		l->tail = n;
	}
	l->size++;
}
Node *removeTail(List *l) {
	if(l->size==0) {
		printf("List -- Error! Trying to remove from empty list");
	} else {
		Node *oldTail = l->tail;
		Node *newTail = l->tail->prev;
		l->tail = newTail;
		if(newTail!=NULL) {
			newTail->next = NULL;
		}  else {
			l->head = l->tail = NULL;
		}
		return oldTail;
	}
	return (Node *)NULL;
}

/*------------------------------------------ Iterator */
/*------------------------------------------ Iterator */

Iterator *newIterator() {
	Iterator *itr = malloc(sizeof(Iterator));
	itr->list = NULL;
	itr->current = NULL;

	return itr;
}
Iterator *initIterator(Iterator *itr, List *l) {
	itr->list = l;
	itr->current = l->head;

	return itr;
}
Iterator *getIterator(List *l) {
	return initIterator(newIterator(), l);
}
void deleteIterator(Iterator *itr) {
	free(itr);
}

Iterator *getListIterator() {
	List *l = newList();
	Iterator *itr = getIterator(l);
	
	l->size = 0;

	return itr;
}

int moveNext(Iterator *itr) {
	if(hasNext(itr->current)==1) {
		itr->current = itr->current->next;
		return 1;
	} else {
		return 0;
	}
}
int movePrev(Iterator *itr) {
	if(hasPrev(itr->current)==1) {
		itr->current = itr->current->prev;
		return 1;
	} else {
		return 0;
	}
}

void dumpTraverse(Iterator *itr) {
	itr->current = itr->list->head;
	do {
		dumpNode(itr->current);
	} while(moveNext(itr)==1);
}

void addElement(Iterator *itr, float data) {
	Node *node = getNode(data);
	addInTail(itr->list, node);
}

float *toArray(Iterator *itr) {
	int i = 0;
	int length = itr->list->size;
	float *array;
	array = malloc(sizeof(float)*length);

	bzero(array, sizeof(float)*length);

	itr->current = itr->list->head;
	do {
		array[i] =  itr->current->data;
		i++;
	} while(moveNext(itr)==1);

	return array;
}

float sum(Iterator *itr) {
	float sum = 0;

	itr->current = itr->list->head;
	do {
		sum += itr->current->data;
	} while(moveNext(itr)==1);
	return sum;
}
float average(Iterator *itr) {
	return sum(itr)/itr->list->size;
}
float deviation(Iterator *itr) {
	float s = 0;
	float a = average(itr);
	float x = 0;

	itr->current = itr->list->head;
	do {
		x = itr->current->data;
		s += pow((x-a), 2);
	} while(moveNext(itr)==1);

	s /= itr->list->size-1;
	return sqrt(s);
}


